package bingosoft.metro.base.service;

import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;

import bingosoft.components.base.helper.AppHelper;
import bingosoft.components.base.helper.ObjectHelper;
import bingosoft.components.base.service.BaseClass;
import bingosoft.components.base.service.ServiceResult;
import bingosoft.metro.base.form.FileForm;
import bingosoft.metro.base.form.ImageForm;
import leap.core.AppContext;
import leap.lang.Strings;
import leap.lang.json.JSON;
import leap.lang.jsoup.helper.StringUtil;

/**
 * @author Feily
 * @功能描述 上传文件服务类
 * @创建时间 2016-12-08
 */
public class UploadService extends BaseClass {

	/** 上传文件根路径 */
	private String uploadRootPath;

	/** 上传文件子路径 */
	private String subPath = "";

	/** 上传文件是否重命名 */
	private boolean isRename = true;

	/**
	 * 构建函数
	 */
	public UploadService() {
		this.setLogClass(this.getClass());
		this.logMethodCalled("UploadService-构建函数");
	}

	/**
	 * 上传文件
	 * 
	 * @param request
	 * @return
	 * @throws Exception
	 */
	public List<FileForm> uploadFiles(HttpServletRequest request) throws Exception {
		this.logMethodCalled("uploadFiles");

		List<FileForm> list = new ArrayList<FileForm>();

		DiskFileItemFactory factory = new DiskFileItemFactory();
		ServletFileUpload upload = new ServletFileUpload(factory);

		List<FileItem> items = upload.parseRequest(request);
		Iterator<FileItem> itr = items.iterator();
		int i = 0;
		while (itr.hasNext()) {
			this.logMessage("" + i);
			FileItem item = (FileItem) itr.next();
			if (!item.isFormField() && item.getName() != null && !item.getName().equals("")) {

				// 上传文件
				FileForm fileForm = this.uploadFile(item);
				list.add(fileForm);
				i++;
			}
		}

		return list;
	}

	/**
	 * 根据图片编码构建图片
	 * 
	 * @param imageCode
	 *            图片编码
	 * @return
	 * @throws Exception
	 */
	public ServiceResult buildImage(String imageStr) throws Exception {
		this.logMethodCalled("buildImage");

		ServiceResult serviceResult = new ServiceResult();
		ImageForm[] images = JSON.decodeArray(imageStr, ImageForm.class);

		int len = images.length;
		this.logParamValue("len", len);
		String uuid = UUID.randomUUID().toString();
		List<String> result = new ArrayList<String>();
		String fileName = uuid + ".png";
		String filePath = this.getSavePath(this.subPath, fileName, this.isRename);

		for (int i = 0; i < images.length; i++) {
			ImageForm image = images[i];

			// 写入磁盘
			Base64.Decoder decoder = Base64.getDecoder();
			byte[] decodedBytes = decoder.decode(image.getImageData()); // 将字符串格式的image转为二进制流（biye[])的decodedBytes

			String fileNewPath = filePath.replaceAll(".png", "_" + image.getResolution() + ".png");

			// 创建上传文件目录
			File file = new File(this.getUploadRootPath() + fileNewPath);
			FileUtils.forceMkdir(file.getParentFile());

			FileOutputStream out = new FileOutputStream(file.getAbsolutePath());
			out.write(decodedBytes); // 利用文件输出器将二进制格式decodedBytes输出
			out.flush(); // 把缓冲区的数据强行输出
			out.close(); // 关闭文件输出器

			result.add(fileNewPath);
		}

		serviceResult.setMessage("上传图片成功！");
		serviceResult.setBusinessObject(result);

		return serviceResult;
	}

	/**
	 * 字符串转二进制
	 * 
	 * @param str
	 *            要转换的字符串
	 * @return 转换后的二进制数组
	 */
	public static byte[] hex2byte(String str) { // 字符串转二进制
		if (str == null)
			return null;
		str = str.trim();
		int len = str.length();
		if (len == 0 || len % 2 == 1)
			return null;
		byte[] b = new byte[len / 2];
		try {
			for (int i = 0; i < str.length(); i += 2) {
				b[i / 2] = (byte) Integer.decode("0X" + str.substring(i, i + 2)).intValue();
			}
			return b;
		} catch (Exception e) {
			return null;
		}
	}

	/**
	 * 上传文件
	 * 
	 * @param item
	 * @return
	 * @throws Exception
	 */
	public FileForm uploadFile(FileItem item) throws Exception {
		// item.getName()返回上传文件在客户端的完整路径名称
		File tempFile = new File(item.getName());
		String fileName = tempFile.getName();
		String filePath = this.getSavePath(this.subPath, fileName, this.isRename);
		
		// 上传文件
		File file = new File(this.getUploadRootPath() + filePath);
		FileUtils.forceMkdir(file.getParentFile());
		item.write(file);
		
		FileForm fileForm = new FileForm();
		fileForm.setName(fileName);
		fileForm.setFilePath(filePath);
		fileForm.setContentType(item.getContentType());
		fileForm.setSize(item.getSize());
		fileForm.setFileUrl(filePath);

		return fileForm;
	}

	/**
	 * 返回文件上传绝对路径
	 * 
	 * @param subPath
	 * @param fileName
	 * @param isRename
	 * @return
	 */
	public String getSavePath(String subPath, String fileName, boolean isRename) {
		// 处理子路径
		if (!StringUtil.isBlank(subPath)) {
			subPath += "/";
		} else {
			subPath = "";
		}

		// 处理日期路径
		Date date = new Date();
		SimpleDateFormat yyyyFt = new SimpleDateFormat("yyyy");
		SimpleDateFormat MMFt = new SimpleDateFormat("MM");
		SimpleDateFormat ddFt = new SimpleDateFormat("dd");
		SimpleDateFormat HHFt = new SimpleDateFormat("HH");
		String datePath = Strings.format("{0}/{1}/{2}/{3}/", yyyyFt.format(date), MMFt.format(date), ddFt.format(date),
				HHFt.format(date));

		// 处理文件名称
		if (isRename) {
			int dotIndex = fileName.lastIndexOf(".");
			String ext = fileName.substring(dotIndex, fileName.length());
			fileName = ObjectHelper.getUUID() + ext;
		}

		return "/" + subPath + datePath + fileName;
	}

	public String getUploadRootPath() {
		if (Strings.isEmpty(uploadRootPath)) {
			// 根据配置文件获取上传根路径
		    String uploadRootPath = AppContext.config().getProperty("runtime.file.rootPath","");
		    Boolean isDev = AppContext.config().getBooleanProperty("runtime.app.dev", true);
		    if(Strings.isEmpty(uploadRootPath) || isDev){
				uploadRootPath = AppHelper.getHome().dir().getAbsolutePath().replace("\\WEB-INF", "").replace("/WEB-INF", "");
			}
			this.uploadRootPath = uploadRootPath;
		}
		return uploadRootPath;
	}
	
	public void setUploadRootPath(String uploadRootPath) {
		this.uploadRootPath = uploadRootPath;
	}

	public String getSubPath() {
		return subPath;
	}

	public void setSubPath(String subPath) {
		this.subPath = subPath;
	}

	public boolean isRename() {
		return isRename;
	}

	public void setRename(boolean isRename) {
		this.isRename = isRename;
	}
}
